/* Copyright (c) CERN
 * * Artistic License 2.0
 * */

import java.util.Random;
import java.lang.Math;
import java.util.Arrays;

/**
 * Uniform distribution
 * This class handles uniform distributions.
 * To make the biased refinements possible it implements an original MoM fitting algorithm
 * i.e. using moments instead of min and max.
 *
 * @author Xavier Grehant
 */
public class Uniform extends DistroUtils implements Distro {

/**
 * Standard deviation.
 */
   double sigma;

/**
 * Mean.
 */
   double mu;

/**
 * Minimum value.
 */
   double min;

/**
 * Maximum value.
 */
   double max;

/**
 * A uniform random generator.
 */
   Random rand;

/**
 * Constructor taking the first and second moments.
 * @param mu mean.
 * @param sigma standard deviation.
 */
   public Uniform(double mu, double sigma) {
      construct(mu, sigma);
   }

/**
 * Constructor taking a sample set.
 * @param array the sample set.
 */
   public Uniform(int[] array) {
      construct(array);
   }

/**
 * This method extracts the instance fields from the first and second moments.
 * @return
 * @param mu mean.
 * @param sigma standard deviation.
 */
   void construct(double mu, double sigma) {
      this.mu = mu;
      this.sigma = sigma;
      min = mu - sigma * Math.sqrt(3);
      max = mu + sigma * Math.sqrt(3);
      System.out.println("mu = " + mu + " sigma = " + sigma + " min = " + min + " max = " + max);
      rand = new Random();
   }

/**
 * This method extracts the instance fields from a sample set.
 * In particular it discards higher values considered noise before parameters estimation.
 * @return
 * @param array the sample set.
 */
   void construct(int[] array) {
      System.out.println("Mean: " + mean(array) + " Std: " + std(array, mean(array)));
      array = discard(array, .01, 10);
      construct(mean(array), std(array, mean(array)));
   }

/**
 * This factory method returns a biased GPD estimation to fit samples over minvalue.
 * @return a Uniform distribution.
 * @param values the sample set.
 * @param minvalue the minimum value of interest.
 * @param refinements the number of times the estimation is biased.
 */
   static Uniform biased(int[] values, int minvalue, int refinements) {
      Uniform u = new Uniform(values);
      for (int refined = 0; refined < refinements; refined++) {
         values = u.bias(values, minvalue);
         u = new Uniform(values);
      }
      return u;
   }

/**
 * Random number generator according to the distribution
 * @return a random number according to the distribution.
 */
   public double nextDouble() {
      return min + rand.nextDouble() * (max - min);
   }

/**
 * Cumulative Density Function according to the distribution.
 * @return the probability to obtain a lower number than the higher bound.
 * @param limit the higher bound.
 */
   public double cdf(int limit) {
      if (limit >= max) return 1; else
      if (limit <= min) return 0; else
      return ((double) limit - (double) min) / ((double) max - (double) min);
   }
}
